Skip to content

Scaffold Swift-implemented drop-in replacement for libbluetooth.so.3 - #63

Open
colemancda wants to merge 53 commits into
masterfrom
feature/c-abi
Open

Scaffold Swift-implemented drop-in replacement for libbluetooth.so.3#63
colemancda wants to merge 53 commits into
masterfrom
feature/c-abi

Conversation

@colemancda

@colemancda colemancda commented Aug 1, 2026

Copy link
Copy Markdown
Member

Summary

Scaffolding for a drop-in, Swift-implemented replacement for BlueZ's shared libbluetooth.so.3. The deliverable is a library that loads, resolves all 218 symbols the reference exports, and fails loudly (by symbol name) on any call not implemented yet — so the rest of the port can proceed incrementally, one symbol family at a time.

Nothing in the bluez package actually links this shared library — bluetoothd, bluetoothctl, btmon, hciconfig and sdptool all statically link libbluetooth-internal.a — so replacing it can't break the Bluetooth stack itself; it exists solely for third-party consumers.

  • Sources/CBluetoothLinuxABI vendors the eleven public BlueZ headers verbatim (GPL-2.0-or-later, isolated in its own directory with its own LICENSE and README) and generates a stub for every symbol not yet implemented, via scripts/gen_stubs.py. Each stub's signature is read out of the vendored headers, so it's checked against the real declaration rather than hand-typed.
  • scripts/symbols.txt records the reference export surface (218, split 17/101/100 across bluetooth.c/hci.c/sdp.c); scripts/implemented.txt records the 203 currently implemented: the bluetooth.c + bt_uuid_* families and the SDP data/list/record/codec layer (both implemented in PureSwift/Bluetooth), plus this repo's own HCI string converter family, HCI device management family, and the 71-symbol HCI command wrapper family (hci_inquiry, hci_create_connection, hci_read_*, hci_write_*, hci_le_*, etc.) — everything BlueZ's lib/hci.c exports except hci_strtoptype-adjacent string helpers already covered above. scripts/gen_symbols.py derives the linker version script and the flat export list from these; scripts/check-exports.sh asserts the built library against it.
  • scripts/ownership.md records the return/who-frees/lifetime contract for each symbol, ahead of implementation — the conventions aren't uniform (some allocate on the heap, some write into a caller buffer, some return static pointers) and guessing produces leaks or double frees no type checker would catch.
  • Sources/BluetoothLinuxABI implements the 21-symbol HCI string converter family, using generated lookup tables (scripts/generate-hci-tables.py, parsed directly from BlueZ's hci.c) for the bus/device-flag/packet-type/link-mode/version/command-name mappings; the 9-symbol HCI device management family (raw AF_BLUETOOTH/BTPROTO_HCI socket open/close, device info/address/id lookup, enumeration, routing, and sending commands/requests); and the 71-symbol HCI command wrapper family (connection/link-policy management, remote-device queries, local controller info, controller configuration, LE commands, and inquiry) built on hciCommand/hciStatus/hciRequest helpers that capture the send/check-status/copy-out shape every wrapper in lib/hci.c repeats. All of it talks to the kernel directly via socket/bind/ioctl/writev/poll rather than through BluetoothLinux's own async HostController/Socket infrastructure, since the ABI surface has to be synchronous and match the reference's wire layout precisely.
  • CMakeLists.txt builds libbluetooth.so.3.19.15 by linking a PureSwift/Bluetooth checkout's static archives (-DBLUETOOTH_PACKAGE_PATH) together with BluetoothLinuxABI and the generated stubs, with the soname, version, and a pinned export list that Package.swift can't express.
  • Conformance/compare.sh and Conformance/conformance_hci_strings.c differentially test the HCI string converter family against the system libbluetooth.so.3; the phase-1 and SDP drivers stay in the PureSwift/Bluetooth checkout alongside the symbols they cover.

Verified

  • The built library exports exactly the 218 expected symbols (check-exports target).
  • Its output over the differential conformance drivers for the symbols with a driver (bluetooth.c/bt_uuid_*, SDP, HCI strings) is identical to the system libbluetooth.so.3, aside from a handful of already-documented deltas (bt_compidtostr naming, one memcmp-magnitude case) recorded in each repo's known-differences.txt.
  • Calling an unimplemented symbol (e.g. hci_open_dev) aborts with libbluetooth (PureSwift): hci_open_dev is not implemented yet. rather than crashing unhelpfully or corrupting state.

Test plan

  • swift build — default configuration, unaffected
  • SWIFTPM_BLUETOOTH_CABI=1 swift build — C ABI target builds
  • SWIFTPM_BLUETOOTH_CABI=1 swift test — passes, including the new BluetoothLinuxABITests
  • cmake -B build -G Ninja -DBLUETOOTH_PACKAGE_PATH=<Bluetooth checkout> && cmake --build buildlibbluetooth.so.3.19.15 builds
  • cmake --build build --target check-exports — 218/218 symbols match
  • Conformance/compare.sh — identical output against the reference library for the HCI string converter driver
  • Smoke test: an unimplemented symbol aborts loudly by name instead of misbehaving

Known gap

hci_send_cmd/hci_send_req and everything built on them — the entire 71-symbol HCI command wrapper family, plus hci_inquiry's ioctl(HCIINQUIRY) call — have not been exercised against a real or virtual HCI device. Only their non-socket paths (input validation, hci_send_cmd's wire-format framing over a plain pipe) are unit tested. No /dev/vhci access was available (root-only in this environment) to build a differential driver for this family; each wrapper is a careful, field-by-field transcription of its lib/hci.c reference, cross-checked against the vendored struct layouts, but unverified end-to-end.

@colemancda colemancda changed the title Add libbluetooth.so.3 scaffolding (phase 0) Add C ABI Aug 1, 2026
Parses hci_map tables and header #define/enum values directly out of
the reference source and emits Swift literal arrays, avoiding manual
transcription of the 232-entry command map and 8x9 feature table.
Bus, device flag, packet type, link policy/mode, version, and command
name tables used by the HCI string converter family, generated from
BlueZ's hci.c via scripts/generate-hci-tables.py.
hci_bustostr, hci_dtypetostr, hci_typetostr, hci_dflagstostr,
hci_ptypetostr/hci_strtoptype, hci_scoptypetostr/hci_strtoscoptype,
hci_lptostr/hci_strtolp, hci_lmtostr/hci_strtolm, hci_cmdtostr,
hci_commandstostr, hci_vertostr/hci_strtover, lmp_vertostr/lmp_strtover,
pal_vertostr/pal_strtover, and lmp_featurestostr — 21 symbols total.

hci_lmtostr intentionally does not replicate the reference's fixed
50-byte buffer overflow for large link-mode masks, and
hci_commandstostr matches the deployed 5.82 library's trailing-space
behavior rather than the 5.85 source tree's trimmed output.
Adds the BluetoothLinuxABI product/target (built against
CBluetoothLinuxABI and Bluetooth's BluetoothABI product for
bt_malloc/bt_free) plus its test target, gated behind
SWIFTPM_BLUETOOTH_CABI=1 alongside the rest of the C ABI surface.
Covers bus, device type, device flags, packet type, link mode,
command name, and version conversions.
Also includes the 75 SDP symbols implemented in the Bluetooth
dependency, so gen_stubs.py stops generating stubs for either family.
Drops the 96 stubs now covered by BluetoothSDP and BluetoothLinuxABI
(105 remaining, 123 implemented).
Exercises all 21 symbols with edge-case inputs (unknown bus/device
values, empty and saturated bitmasks, malformed parse strings). Links
directly against the system libbluetooth.so.3 since all 21 symbols
are exported by it.
Builds conformance_hci_strings.c against both the system reference
and libBluetoothLinuxABI.so and diffs the output, using the same
known-differences.txt convention as the Bluetooth checkout. The
phase-1 and SDP drivers stay in the Bluetooth checkout alongside the
symbols they cover.
Adds a BluetoothLinuxABI static library target and links it, along
with BluetoothSDP, into the final bluetooth3 artifact via
--whole-archive. BluetoothSDP was previously implemented but never
actually linked into the CMake build.
@colemancda colemancda changed the title Add C ABI Scaffold Swift-implemented drop-in replacement for libbluetooth.so.3 Aug 2, 2026
hci_open_dev, hci_close_dev, hci_devinfo, hci_devba, hci_devid,
hci_for_each_dev, hci_get_route, hci_send_cmd, and hci_send_req — the
raw AF_BLUETOOTH/BTPROTO_HCI socket layer that the rest of the HCI
command wrappers build on. These call socket/bind/ioctl/writev/poll
directly rather than routing through BluetoothLinux's own async
HostController/Socket infrastructure, since the ABI surface has to be
synchronous and match the reference's wire layout precisely.

hci_send_cmd and hci_send_req haven't been exercised against a real
or virtual HCI device yet — no differential conformance harness for
this family exists.
Covers only what doesn't require a real or virtual adapter: input
validation that returns before any socket is touched, and
hci_send_cmd's wire format, verified over a plain pipe.
Drops the 9 stubs now covered by BluetoothLinuxABI's device
management family (96 remaining, 132 implemented).
hciCommand/hciStatus/hciRequest capture the send/check-status/copy-out
shapes that every hci_send_req-based command wrapper in lib/hci.c
repeats, so each wrapper is a short, direct transcription of its
reference instead of duplicating the boilerplate.
hci_create_connection, hci_disconnect, hci_authenticate_link,
hci_encrypt_link, hci_change_link_key, hci_switch_role, hci_park_mode,
and hci_exit_park_mode.
hci_read_remote_name(_with_clock_offset), hci_read_remote_name_cancel,
hci_read_remote_version, hci_read_remote_features,
hci_read_remote_ext_features, and hci_read_clock_offset.
hci_read_local_version, hci_read_local_commands, hci_read_local_features,
hci_read_local_ext_features, hci_read_bd_addr, hci_read_local_name, and
hci_write_local_name.
White list and resolving list management, scan and advertising
control, and LE connection establishment/update/remote-features
query.
Class of device, voice setting, inquiry access codes, stored link
keys, inquiry/AFH/inquiry-mode toggles, extended inquiry response,
simple pairing, OOB data, transmit power, link policy/supervision
timeout, AFH classification, and per-connection link quality/RSSI/AFH
map/clock queries — 33 symbols.
Unlike the rest of the command wrapper family, this goes through a
single ioctl(HCIINQUIRY) rather than hci_send_req — the request header
and resulting inquiry_info records share one kernel buffer, the same
shape as HCIGETDEVLIST in HCIDevice.swift.
Drops the 71 stubs now covered by the HCI command wrapper family (25
remaining — the SDP session functions — 203 implemented).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant